package uk.ac.aber.paws.server.autosleep;

import java.util.*;
import java.util.logging.Level;
import uk.ac.aber.paws.server.core.PAWSServer;

/**
 * @author Rob Johnson, Aberystwyth University
 * @email rob.johnson@aber.ac.uk
 * @date 21st May 2012
 * 
 * SleepProfile.java
 * 
 * This class stores the profile information from the database. Once instance of this class per entry from the database.
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public class SleepProfile {

	private String computerFilter;
	private String ou;
	private int inheritance;
	private int enabled;
	private String sleepMode;
	private String sleepIntervalStart;
	private String sleepIntervalEnd;
	private int idlePeriod;
	private String days;
	private String alias;
	
	public SleepProfile(Hashtable<String,Object> profileInfo) {
		
		this.computerFilter = (String)profileInfo.get("Filter");
		this.ou = (String)profileInfo.get("OU");
		this.inheritance = ((Integer)profileInfo.get("Inheritance")).intValue();
		this.enabled = ((Integer)profileInfo.get("Enabled")).intValue();
		this.sleepMode = (String)profileInfo.get("SleepMode");
		this.sleepIntervalStart = (String)profileInfo.get("SleepPeriodStart");
		this.sleepIntervalEnd = (String)profileInfo.get("SleepPeriodEnd");
		this.idlePeriod = ((Integer)profileInfo.get("IdlePeriod")).intValue();
		this.days = (String)profileInfo.get("Days");
		this.alias = (String)profileInfo.get("FQDN");
	}
	
	public String getTopLevelOU() {
		
		return this.ou;
	}
	
	public boolean isEnabled() {
		
		if (enabled == 1) {
			return true;
		}
		
		return false;
	}
	
	/**
	 * Given a last logout time, checks whether this should warrant a sleep for this profile
	 * @param lastLogout The time since 1970ish of the last logout in milliseconds
	 * @return Returns true if the computer should sleep based on this profile
	 */
	public boolean checkForSleepRequirement(long lastHit) {
		
		// get the current time
		long currentTime = Calendar.getInstance().getTimeInMillis();
		
		// get the current day of the week
		int currentDayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
		
		PAWSServer.LOG_FILE.log(Level.ALL,new Date(currentTime).toString());
		
		Hashtable<String,Long> lastLogin = new Hashtable<String,Long>();
		lastLogin.put("lastlogin", currentTime-lastHit);
		
		return isItAHit(currentDayOfWeek,lastLogin);
	}

	/**
	 * Given a last logout time, checks whether this should warrant a sleep for this profile
	 * @param lastLogout The time since 1970ish of the last logout in millisecoonds
	 * @return Returns true if the computer should sleep based on this profile
	 */
	public boolean checkForIdleSleepRequirement(Hashtable<String,Long> idleTimes) {
		
		// get the current day of the week
		int currentDayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
		
		return isItAHit(currentDayOfWeek,idleTimes);
	}
	
	public boolean isItTimeToSleep() {
		
		int currentDayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
		
		if (this.enabled == 1) {
			
			// validate that the day index               
			if (checkDay(currentDayOfWeek)) {
					
				// validate the currentTime
				if (checkTime()) {	
					return true;
				}
			}
		}
		
		return false;
	}
	
	public String getComputerFilter() {
		
		return this.computerFilter;	
	}
	
	public String getSleepMode() {
		
		return this.sleepMode;
	}
	
	public String getAlias() {
		
		return this.alias;
	}
	
	public int getInheritance() {
		
		return this.inheritance;
	}
	
	public boolean isItAHit(int currentDayOfWeek, Hashtable<String,Long> idleTimes) {
		
		if (this.enabled == 1) {
			
			// validate that the day index               
			if (checkDay(currentDayOfWeek)) {
		
				// validate the currentTime
				if (checkTime()) {
			
					// validate the sleep period
					if (checkSleep(idleTimes)){
					
						return true;
					}
				}
			}
		}
		
		return false;
	}
	
	private boolean checkSleep(Hashtable<String,Long> idleTimes) {
		
		Enumeration<String> keys = idleTimes.keys();
		boolean userDetected = false;
		
		while (keys.hasMoreElements()) {
			
			userDetected = true;
			
			Long thisIdle = idleTimes.get(keys.nextElement());
			
			if (thisIdle.longValue() <= (new Long(this.idlePeriod).longValue()*60l*1000l)) {
				return false;
			}
		}
		
		if (!userDetected) {
			return false;
		}
		
		return true;
	}
	
	private boolean checkTime() {
		
		TimeDef thisTime = new TimeDef(this.sleepIntervalStart);
		
		Calendar minCal = Calendar.getInstance();
		minCal.set(Calendar.HOUR_OF_DAY, thisTime.getHour());
		minCal.set(Calendar.MINUTE, thisTime.getMin());
		minCal.set(Calendar.SECOND, 0);
	
		thisTime = new TimeDef(this.sleepIntervalEnd);
		
		Calendar maxCal = Calendar.getInstance();
		maxCal.set(Calendar.HOUR_OF_DAY, thisTime.getHour());
		maxCal.set(Calendar.MINUTE, thisTime.getMin());
		maxCal.set(Calendar.SECOND, 59);
		
		Calendar now = Calendar.getInstance();
		
		if (now.getTimeInMillis() > minCal.getTimeInMillis() && now.getTimeInMillis() < maxCal.getTimeInMillis()) {
			return true;
		}
			
		return false;
	}
	
	private boolean checkDay(int currentDayOfWeek) {
		
		StringTokenizer st = new StringTokenizer(this.days,",");
		
		if (st.countTokens() > 0) {
			
			while (st.hasMoreElements()) {
				
				String day = st.nextToken();
				
				if (Integer.parseInt(day) == currentDayOfWeek) {
					return true;
				}
			}
		}
		
		return false;
	}
	
	class TimeDef {
		
		private int hour = -1;
		private int min = -1;
		
		public int getHour() {
			return hour;
		}
		
		public int getMin() {
			return min;
		}
		
		TimeDef(String timeValue) {
		
			
			StringTokenizer st = new StringTokenizer(timeValue,":");
			
			if (st.countTokens() == 2) {
			
				hour = Integer.parseInt(st.nextToken());
				min = Integer.parseInt(st.nextToken());
		
			}
			
		}
	}

}
